package com.chat.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chat.system.entity.dto.ChatRecordDTO;
import com.chat.system.entity.dto.ChatUserDTO;
import com.chat.system.entity.dto.LatelyChatFriendDTO;
import com.chat.system.entity.po.ChatUser;
import com.chat.system.entity.po.ChatUserRelationship;
import com.chat.system.entity.po.LatelyChatSession;
import com.chat.system.mapper.ChatUserMapper;
import com.chat.system.service.IChatUserRelationshipService;
import com.chat.system.service.IChatUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chat.system.utils.UserUtil;
import com.chat.wesocket.entity.WsMessage;
import com.chat.wesocket.handler.WsHandler;
import org.apache.logging.log4j.util.Base64Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.web.socket.WebSocketSession;

import java.io.*;
import java.nio.charset.Charset;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.chat.wesocket.entity.WsMessage.EVENT_STOP_VIDEO;
import static javax.xml.bind.DatatypeConverter.parseBase64Binary;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author czh
 * @since 2023-10-27
 */
@Service
public class ChatUserServiceImpl extends ServiceImpl<ChatUserMapper, ChatUser> implements IChatUserService {

    @Value("${czh.filePath}")
    String pathPrefix;
    @Autowired
    ChatUserMapper chatUserMapper;
    @Autowired
    IChatUserRelationshipService chatUserRelationshipService;
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    WsHandler wsHandler;
    public static final Integer PAGE_SIZE = 10;

    @Override
    public List<ChatUserDTO> listChatUsers(String userName,String currentUserName) {

        return chatUserMapper.listChatUsers(userName,currentUserName);
    }

    @Override
    public void beginNewChat(String relationshipID, String message) {
        final String currentUserName = UserUtil.getCurrentUserName();
        final ChatUserRelationship relationship = chatUserRelationshipService.getById(relationshipID);

        if (relationship != null) {
            LatelyChatSession latelyChatSession = new LatelyChatSession();
            latelyChatSession.setId(relationshipID);
            latelyChatSession.setLastDate(new Date());
            latelyChatSession.setLastMessage(message);

            mongoTemplate.save(latelyChatSession);
            //TODO advice
            if (!message.equals("") ){

            }
        }
    }


    @Override
    public List<LatelyChatFriendDTO> getLatelyFriendList(String currentUserName) {
        QueryWrapper<ChatUserRelationship> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name",currentUserName).or().eq("friend_name",currentUserName);
        final List<ChatUserRelationship> list = chatUserRelationshipService.list(queryWrapper);

        final List<String> idList = list.stream().map(ChatUserRelationship::getId).collect(Collectors.toList());

        final Query query = new Query();
        query.addCriteria(new Criteria("id").in(idList));
        final List<LatelyChatSession> latelyChatSessions = mongoTemplate.find(query, LatelyChatSession.class);

        List<LatelyChatFriendDTO> friendList = new ArrayList<>(latelyChatSessions.size());
        for (LatelyChatSession latelyChatSession : latelyChatSessions) {
            final List<ChatUserRelationship> relationship = list.stream().filter(x -> x.getId().equals(latelyChatSession.getId())).collect(Collectors.toList());
            if (relationship.size() != 1) {
                throw new RuntimeException("aaaaaaaaaaaaa");
            }
            DateFormatter formatter = new DateFormatter("hh:mm");
            final String lastDate = formatter.print(latelyChatSession.getLastDate(), Locale.CHINA);
            final String currentFriendName = UserUtil.getCurrentFriendName(currentUserName, relationship.get(0));
            friendList.add(new LatelyChatFriendDTO(latelyChatSession.getId(),
                    currentFriendName,
                    lastDate,
                    latelyChatSession.getLastMessage()));
        }

        return friendList;
    }

    @Override
    public Map<String, Map<String ,Object>> getLatelyChatRecords(String currentUserName) {
        final List<LatelyChatFriendDTO> latelyFriendList = getLatelyFriendList(currentUserName);
        Map<String, Map<String ,Object>> map =  new HashMap<>(latelyFriendList.size());
        for (LatelyChatFriendDTO latelyChatFriendDTO : latelyFriendList) {
            final String relationShipId = latelyChatFriendDTO.getId();
            Query query = new Query();
            query.addCriteria(new Criteria("relationshipId").is(relationShipId));
            // 拿到最近十条
            long count = mongoTemplate.count(query, ChatRecordDTO.class);
            query.skip(count - 10);
            final List<ChatRecordDTO> chatRecordDTOS = mongoTemplate.find(query, ChatRecordDTO.class);

            chatRecordDTOS.sort(Comparator.comparing(ChatRecordDTO::getDate));
            Map<String ,Object> res = new HashMap<>();
            res.put("records",chatRecordDTOS);
            res.put("totalNumberOfRecords",count);
            res.put("current",1);
            map.put(relationShipId,res);
        }
        return map;
    }
    @Override
    public long getTotalNumOfLatelyChatRecord(String currentUserName) {

        return 0;
    }

    @Override
    public List<ChatRecordDTO> fetchChatRecords(String friendShipId, Long current, Long total) {
        current++;
        Query query = new Query();
        query.addCriteria(new Criteria("relationshipId").is(friendShipId));
        Integer skip = Integer.parseInt(String.valueOf((total - current * PAGE_SIZE)));
        if (skip <= -10){
            return new ArrayList<>();
        }
        query.skip(skip);
        int pageSize = Integer.parseInt(PAGE_SIZE.toString());
        query.limit(skip < 0 ?  (pageSize + skip) : pageSize);
        List<ChatRecordDTO> chatRecordDTOS = mongoTemplate.find(query, ChatRecordDTO.class);
        return chatRecordDTOS;
    }

    @Override
    public void sendMessage(ChatRecordDTO chatRecordDTO) {
        chatRecordDTO.setDate(new Date());
//        processContent(chatRecordDTO);
        //更新最近通信
        final String relationshipId = chatRecordDTO.getRelationshipId();
        LatelyChatSession latelyChatSession = mongoTemplate.findOne(new Query(new Criteria("id").is(relationshipId)), LatelyChatSession.class);
        String content = chatRecordDTO.getContent().contains("<img ")? "[图片]": chatRecordDTO.getContent();
        if (latelyChatSession != null) {
            latelyChatSession.setLastDate(chatRecordDTO.getDate());
            latelyChatSession.setLastMessage(content);
            mongoTemplate.save(latelyChatSession);
        }else{
            //添加最近通信

            latelyChatSession = new LatelyChatSession(content,chatRecordDTO.getDate());
            mongoTemplate.save(latelyChatSession);
        }

        if (chatRecordDTO.getContent().contains("<img ")){
//            handleImg(chatRecordDTO);
        }

        //通知 新的聊天记录将聊天记录添加到
        mongoTemplate.save(chatRecordDTO);

        final WebSocketSession online = wsHandler.isOnline(chatRecordDTO.getTo());
        if (online != null) {
            //TODO ws 通知 并且更改最近通信的消息
            WsMessage wsMessage = new WsMessage(WsMessage.EVENT_NEW_MESSAGE_RECEIVE);
            wsMessage.put("msg",chatRecordDTO);
            try {
                online.sendMessage(wsMessage.toMessage());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //TODO 提取 src。
    private void handleImg(ChatRecordDTO chatRecordDTO) {
        String content = chatRecordDTO.getContent();
        String[] split = content.split("<img ");
        for (int i = 0; i < split.length; i++) {
            String src = extractImageSrc("<img " + split[i]);
            if (src == null || src.startsWith("http")) {
                continue;
            }
            String url =  base64SaveToDisk(src,chatRecordDTO.getRelationshipId());
            split[i] = split[i].replace(src,url);
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (String s : split) {
            if (s.startsWith("src=")) {
                stringBuilder.append("<img ").append(s);
            }else {
                stringBuilder.append(s);
            }
        }
        chatRecordDTO.setContent(stringBuilder.toString());
    }

    private String base64SaveToDisk(String src,String relationshipId) {
        ChatUserRelationship relationship = chatUserRelationshipService.getById(relationshipId);
        String filePath =  relationship.getResPath() + File.separator;
        String fileName =  UUID.randomUUID().toString() + "."+ src.substring(src.indexOf("/") + 1 ,src.indexOf(";"));
        new Thread(() -> {
            convertBase64ToFile(src,filePath,fileName);
        }).start();
        return "api" + File.separator +"img" + File.separator + filePath + fileName;
    }
//    /Users/dadigua/var/filePath-chat
    public  void convertBase64ToFile(String base64String, String filePath,String fileName) {
        File file = new File(pathPrefix +filePath);
        if (!file.exists()) {
            file.mkdir();
        }
        try  {
            FileOutputStream outputStream = new FileOutputStream(pathPrefix + filePath + fileName);

            byte[] fileBytes = parseBase64Binary(base64String.split(",")[1]);

            outputStream.write(fileBytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String extractImageSrc(String html) {
        String pattern = "<img[^>]+src\\s*=\\s*['\"]([^'\"]+)['\"][^>]*>";
        Pattern imgTagPattern = Pattern.compile(pattern);
        Matcher matcher = imgTagPattern.matcher(html);

        if (matcher.find()) {
            return matcher.group(1);
        }
        return null; // 如果没有找到匹配的 img 标签
    }
    @Override
    public boolean checkOnline(String friendName) {
        final WebSocketSession online = wsHandler.isOnline(friendName);
        return online != null;
    }

    @Override
    public void videoInvite(String friendName) {
        final WebSocketSession online = wsHandler.isOnline(friendName);
        if (online != null) {
            WsMessage wsMessage = new WsMessage(WsMessage.EVENT_VIDEO_INVITE);
            wsMessage.put("from",UserUtil.getCurrentUserName());
            try {
                online.sendMessage(wsMessage.toMessage());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void videoInviteConfirm(String friendName, boolean confirm) {
        final WebSocketSession online = wsHandler.isOnline(friendName);
        if (online != null) {
            WsMessage wsMessage = new WsMessage(WsMessage.EVENT_INVITE_CONFIRM);
            wsMessage.put("confirm",confirm);
            try {
                synchronized (online){
                    online.sendMessage(wsMessage.toMessage());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void stopVideo(String friendName) {
        WebSocketSession online = wsHandler.isOnline(friendName);
        if (online != null) {
            WsMessage wsMessage = new WsMessage(EVENT_STOP_VIDEO);
            try {
                online.sendMessage(wsMessage.toMessage());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public ChatRecordDTO preHandleIMG(ChatRecordDTO chatRecordDTO) {
        handleImg(chatRecordDTO);
        return chatRecordDTO;
    }



    private void processContent(ChatRecordDTO chatRecordDTO) {
        final String content = chatRecordDTO.getContent();
        final String[] split = content.split("<img ");
        StringBuilder builder = new StringBuilder();
        for (String s : split) {
            if (s.startsWith("src=")){
                builder.append("<img style='width:300px' ").append(s);
            }else{
                builder.append(s);
            }
        }
        chatRecordDTO.setContent(builder.toString());
    }
}
